package com.milling.web.utils;

import com.alibaba.fastjson2.JSONObject;
import com.milling.business.BusinessConstants;
import com.milling.business.GlobalVariable;
import com.milling.business.domain.WmsSortingInstockHistory;
import com.milling.business.service.IWmsSortingInstockHistoryService;
import com.milling.business.service.SuspendTaskManager;
import com.milling.common.core.redis.RedisCache;
import com.milling.common.utils.SocketUtils;
import com.milling.common.utils.StringUtils;
import com.milling.common.utils.http.WmsApiUtils;
import com.milling.common.utils.modbus.ModbusServiceFactory;
import com.milling.common.utils.modbus.ModbusTcpService;
import com.milling.common.utils.scanner.SocketListener;
import com.milling.common.utils.uuid.UUID;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;

@Configuration
@ConditionalOnProperty(
        name = "mac.type",
        havingValue = "9",
        matchIfMissing = false // 当配置缺失时不加载
)
//@Component
public class InstockScannerII implements SocketListener.MessageCallback {
    private static final Logger logger = LoggerFactory.getLogger(InstockScannerII.class);

    @Value("${sorting.scanner.instockip}")
    private String instockIp;

    @Value("${sorting.scanner.port}")
    private int instockPort;

    @Autowired
    private SuspendTaskManager suspendTaskManager;

    private SocketUtils socketUtils; // 声明为成员变量

    // 从参数中读取IP、端口、slaveId和连接池大小
    @Value("${modbus.sorting.host:192.168.237.178}")
    private String host; // 从配置文件或命令行参数中读取

    @Value("${modbus.sorting.port:502}")
    private int port; // 从配置文件或命令行参数中读取

    @Value("${modbus.sorting.poolSize:5}")
    private int poolSize; // 从配置文件或命令行参数中读取

    @Value("${modbus.sorting.slaveId:1}")
    private int slaveId;

    @Autowired
    private IWmsSortingInstockHistoryService wmsSortingInstockHistoryService;

    // 获取Modbus服务实例
    private ModbusTcpService modbusTcpService;
    @Autowired
    private RedisCache redisCache;

    @PostConstruct
    public void init() {
        // 初始化 Modbus 服务
        modbusTcpService = ModbusServiceFactory.getModbusService(host, port, poolSize);
        logger.info("InstockScanner Modbus服务初始化完成 - {}:{}", host, port);

        // 初始化扫码器连接
        // 注意：SortingScanner 使用按需连接方式，不需要持久连接
    }

    @Autowired
    public InstockScannerII(@Value("${sorting.scanner.instockip}") String instockIp, @Value("${sorting.scanner.port}") int instockPort) {
        this.instockIp = instockIp;
        this.instockPort = instockPort;
        this.socketUtils = new SocketUtils(instockIp, instockPort); // 初始化
    }

    @Override
    public void onMessageReceived(String message) {
        // 创建连接池

//        logger.error("[分拣机扫码结果] " + message);
//        if("NoRead".equals(message)){
        if(message.contains("NoRead")){
            // 修复无限重试问题：添加扫码次数限制
            if(GlobalVariable.maxScanTimes <= 20) {
                GlobalVariable.maxScanTimes = GlobalVariable.maxScanTimes + 1;
                try {
                    //扫码 - 使用try-with-resources确保资源正确释放
                    try (SocketUtils tempSocketUtils = new SocketUtils(instockIp, instockPort)) {
                        tempSocketUtils.sendMessage("start");
                        Thread.sleep(50);
                    }
                } catch (Exception e) {
                    logger.error("[PLC]入库扫码器扫码失败", e);
                    try {
                        modbusTcpService.writeHoldingRegister(slaveId,5021, 2);//扫码失败，信号回写2
                        logger.info("[PLC]入库扫码器扫码成功，给5021地址写2成功");
                    } catch (ModbusTransportException ex) {
                        ex.printStackTrace();
                        logger.info("[PLC]入库扫码器扫码失败，给5021地址写2失败");
                    } catch (Exception ex) {
                        ex.printStackTrace();
                        logger.info("[PLC]入库扫码器扫码成功，给5021地址写2失败");
                    }
                }
            } else {
                // 超过最大重试次数，重置计数器并记录错误
                GlobalVariable.maxScanTimes = 0;
                logger.error("入库扫码器扫码失败次数超过限制，已重置扫码计数器");
                // 可以在这里添加报警逻辑
            }
        } else {
            // 扫码成功，重置扫码次数
            synchronized(this) {
                GlobalVariable.maxScanTimes = 0;
            }
            logger.info("入库扫码结果 " + message);

            try {
                modbusTcpService.writeHoldingRegister(slaveId,5021, 1);//扫码成功，信号回写1
                logger.info("[PLC]入库扫码器扫码成功，给5021地址写1成功");
            } catch (ModbusTransportException ex) {
                ex.printStackTrace();
                logger.info("[PLC]入库扫码器扫码失败，给5021地址写1失败");
            } catch (Exception ex) {
                ex.printStackTrace();
                logger.info("[PLC]入库扫码器扫码成功，给5021地址写1失败");
            }
            //绑定二维码
            bindData(message);
        }
    }

    @Override
    public void onConnectionClosed() {
        System.out.println("[INFO] SortingScanner Connection closed by server");
    }

    @Override
    public void onError(String errorMsg) {
        System.err.println("[ERROR] " + errorMsg);
    }

    private int getIntCache(String key) {
        return redisCache.getCacheObject(key) == null ? 0 : (int) redisCache.getCacheObject(key);
    }

    private String getStringCache(String key) {
        return redisCache.getCacheObject(key) == null ? "" : (String) redisCache.getCacheObject(key);
    }

    private void bindData(String qrcode) {
        try {
            WmsSortingInstockHistory instockHistory = new WmsSortingInstockHistory();
            instockHistory.setStatus(BusinessConstants.SORTING_INSTOCK_STATUS_WAIT);
            List<WmsSortingInstockHistory> instockHistoryList = wmsSortingInstockHistoryService.selectWmsSortingInstockHistoryList(instockHistory);
            if(null != instockHistoryList && instockHistoryList.size() > 0) {
                WmsSortingInstockHistory updateInstockHistory = instockHistoryList.get(0);
                logger.info("入库针盒记录： " + updateInstockHistory.getId().toString());
                //写入请求包 及 交易码
                String transCode = UUID.randomUUID().toString();
                updateInstockHistory.setTransCode(transCode);
                updateInstockHistory.setBoxCode(qrcode);
                updateInstockHistory.setUpdateTime(new Date());
                JSONObject jsonObject = genPostData(updateInstockHistory);
                updateInstockHistory.setReqBody(jsonObject.toString());
                updateInstockHistory.setStatus(BusinessConstants.SORTING_INSTOCK_STATUS_INSTOCKING);//待入库
                wmsSortingInstockHistoryService.updateWmsSortingInstockHistory(updateInstockHistory);

                WmsApiUtils wmsApiUtils = new WmsApiUtils();
                String result = wmsApiUtils.sortingInStock(jsonObject.toString());
                if(StringUtils.isNotEmpty(result)) {
                    JSONObject jsonObject2 = JSONObject.parseObject(result);
                    // 提取顶层字段
                    String code = jsonObject2.getString("Code");
                    String message = jsonObject2.getString("Message");

                    if("0".equals(code)) {
                        logger.info("通知WMS分拣入库钻针信息成功：" + message);
                    } else {
                        logger.error("通知WMS分拣入库钻针信息失败，错误信息：" + message);
                    }
                } else {
                    logger.error("通知WMS分拣入库钻针信息失败，返回结果为空");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private JSONObject genPostData(WmsSortingInstockHistory instockHistory) {
        String drillDirection = "1";    //钻针方向 倒插
        String grindStatus = "0";    //研磨状态 待磨
        String boxType = "01";    //针盒类型 成盅盒
        String m_Drill_Status = calcDrillStatus(drillDirection, grindStatus, boxType);
        String m_Drill_Kepp = "0"; //保留位

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("MacCode", "B001");
        jsonObject.put("TransCode", instockHistory.getTransCode());
        jsonObject.put("BoxId", instockHistory.getBoxCode());
        jsonObject.put("Drillinfo", "");
        jsonObject.put("m_Drill_Info", instockHistory.getDrillInfo());
        jsonObject.put("m_Drill_Size", instockHistory.getDrillSize());
        jsonObject.put("m_Drill_Type", instockHistory.getDrillType());
        jsonObject.put("m_Drill_Edge", instockHistory.getDrillEdge());
        jsonObject.put("m_Drill_Factory", instockHistory.getDrillFactory());
        jsonObject.put("m_Drill_Count", instockHistory.getDrillCount().toString());//转换类型
        jsonObject.put("m_Drill_GrindCount", instockHistory.getDrillGrindCount().toString());//转换类型
        jsonObject.put("m_Drill_Status", m_Drill_Status);
        jsonObject.put("m_Drill_Kepp", m_Drill_Kepp);
        jsonObject.put("Timestamp", instockHistory.getUpdateTime());
        return jsonObject;
    }

    private String calcDrillStatus(String drillDirection, String grindStatus, String boxType) {
        String m_Drill_Status = "0"; // 初始值根据需求设置
        String drillStatus = drillDirection  + grindStatus + boxType; //拼接字符串 钻针方向 + 研磨状态 + 针盒类型
        switch (drillStatus) {
            case "0000":
                m_Drill_Status = "0";
                break;
            case "0001":
                m_Drill_Status = "1";
                break;
            case "0010":
                m_Drill_Status = "2";
                break;
            case "0011":
                m_Drill_Status = "3";
                break;
            case "0100":
                m_Drill_Status = "4";
                break;
            case "0101":
                m_Drill_Status = "5";
                break;
            case "0110":
                m_Drill_Status = "6";
                break;
            case "0111":
                m_Drill_Status = "7";
                break;
            case "1000":
                m_Drill_Status = "8";
                break;
            case "1001":
                m_Drill_Status = "9";
                break;
            case "1010":
                m_Drill_Status = "A";
                break;
            case "1011":
                m_Drill_Status = "B";
                break;
            case "1100":
                m_Drill_Status = "C";
                break;
            case "1101":
                m_Drill_Status = "D";
                break;
            case "1110":
                m_Drill_Status = "E";
                break;
            case "1111":
                m_Drill_Status = "F";
                break;
            default:
                logger.error("未知的钻探状态，无效的参数");
                // 可添加默认情况的处理逻辑
                break;
        }
        return m_Drill_Status;
    }

}
